import cv2 as cv
import numpy as np
import time


def color_deal(img, deal_Type):
    """根据用户的选择，对于图像做相应的处理"""
    if img.shape[-1] != 3 and deal_Type != 1:
        pass
    if deal_Type == 1:
        #手写图像取反色处理
        time1 = time.time()
        # width = img.shape[1]
        # height = img.shape[0]
        # if img.shape[-1] == 3:
        #     for row in range(height):  # 遍历每一行
        #         for col in range(width):  # 遍历每一列
        #             for channel in range(3):  # 遍历每个通道（三个通道分别是BGR）
        #                 img[row][col][channel] = 255 - img[row][col][channel]
        # else:
        #     for row in range(height):  # 遍历每一行
        #         for col in range(width):  # 遍历每一列
        #             img[row][col] = 255 - img[row][col]
        img = 255 - img
        time2 = time.time()
        print("数据检索遍历时间：", (time2 - time1) * 1000)
        # opencv求反色函数
    #     time1 = time.time()
    #     img = cv.bitwise_not(img)
    #     time2 = time.time()
    #     print("opencv遍历时间：", (time2 - time1) * 1000)
    #
    elif deal_Type == 2:
        img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    elif deal_Type == 3:
        img = cv.cvtColor(img, cv.COLOR_BGR2Lab)
    elif deal_Type == 4:
        img = cv.cvtColor(img, cv.COLOR_BGR2YCrCb)
    elif deal_Type == 5:
        img = cv.cvtColor(img, cv.COLOR_BGR2HSV)
    else:
        pass
    return img


def img_sample(img, interval):
    """
    对图像进行采样处理
    :param img: 输入图像
    :param interval: 采样间隔（每隔interval个像素采样一次）
    :return: 采样后的图像
    """
    if interval == 0:
        return img
    start_time = time.time()
    # 计算采样后的图像尺寸
    height, width = img.shape[:2]
    new_height = height // (interval + 1)
    new_width = width // (interval + 1)

    # 创建新图像
    if len(img.shape) == 3:  # 彩色图像
        sampled_img = np.zeros((new_height, new_width, img.shape[2]), dtype=img.dtype)
        for i in range(new_height):
            for j in range(new_width):
                sampled_img[i, j] = img[i * (interval + 1), j * (interval + 1)]
    else:  # 灰度图像
        sampled_img = np.zeros((new_height, new_width), dtype=img.dtype)
        for i in range(new_height):
            for j in range(new_width):
                sampled_img[i, j] = img[i * (interval + 1), j * (interval + 1)]

    # # 使用OpenCV的resize函数进行采样3（使用最近邻插值）
    # sampled_img = cv.resize(img, (new_width, new_height), interpolation=cv.INTER_NEAREST)
    #
    # end_time = time.time()
    # processing_time = (end_time - start_time) * 1000  # 转换为毫秒
    # print("采样数据检索遍历时间：", processing_time)
    return sampled_img


def img_quanty(img, levels):
    """
    对图像进行量化处理
    :param img: 输入图像
    :param levels: 量化级别（将像素值量化为levels个级别）
    :return: 量化后的图像
    """
    if levels <= 1:
        return img
        # 确保输入图像是uint8类型
    if img.dtype != np.uint8:
        img = img.astype(np.uint8)

    start_time = time.time()

    # 确保levels在合理范围内
    levels = max(2, min(levels, 256))

    # 计算量化步长
    step = 256 / levels

    # 创建量化查找表
    quantize_map = np.zeros(256, dtype=np.uint8)
    for i in range(256):
        quantize_map[i] = int(i / step) * step + step / 2

    # 应用量化
    if len(img.shape) == 3:  # 彩色图像
        quantized_img = np.zeros_like(img)
        for c in range(img.shape[2]):
            quantized_img[:, :, c] = quantize_map[img[:, :, c]]
    else:  # 灰度图像
        quantized_img = quantize_map[img]

    # 使用OpenCV的LUT函数进行量化
    # # 创建查找表
    # lut = np.zeros(256, dtype=np.uint8)
    # for i in range(256):
    #     # 计算量化后的值（使用四舍五入而不是截断）
    #     quantized_value = round(i / step) * step
    #     # 确保值在0-255范围内
    #     lut[i] = np.uint8(max(0, min(255, int(quantized_value))))
    #
    # # 应用查找表
    # quantized_img = cv.LUT(img, lut)

    end_time = time.time()
    processing_time = (end_time - start_time) * 1000  # 转换为毫秒
    print("量化数据检索遍历时间：", processing_time)
    return quantized_img


def non_uniform_sampling_edge_based(img, base_interval, edge_interval):
    """
    基于边缘检测的非均匀采样
    :param img: 输入图像
    :param base_interval: 基础采样间隔（用于平滑区域）
    :param edge_interval: 边缘区域采样间隔（通常小于基础间隔）
    :return: 采样后的图像
    """
    # 转换为灰度图像
    if len(img.shape) == 3:
        # gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        # 使用加权平均法计算灰度值
        gray = np.dot(img[..., :3], [0.2989, 0.5870, 0.1140]).astype(np.uint8)
    else:
        gray = img

    # 手写Canny边缘检测
    def canny_edge_detection(image, low_threshold=100, high_threshold=200):
        """手写简化版Canny边缘检测"""

        # 高斯模糊
        def gaussian_blur(img, kernel_size=5, sigma=1.4):
            """手写高斯模糊"""
            # 创建高斯核
            kernel = np.zeros((kernel_size, kernel_size))
            center = kernel_size // 2
            for i in range(kernel_size):
                for j in range(kernel_size):
                    x, y = i - center, j - center
                    kernel[i, j] = np.exp(-(x ** 2 + y ** 2) / (2 * sigma ** 2))
            kernel /= np.sum(kernel)

            # 应用卷积
            pad_size = kernel_size // 2
            padded = np.pad(img, pad_size, mode='reflect')
            blurred = np.zeros_like(img, dtype=np.float32)

            for i in range(img.shape[0]):
                for j in range(img.shape[1]):
                    region = padded[i:i + kernel_size, j:j + kernel_size]
                    blurred[i, j] = np.sum(region * kernel)

            return blurred.astype(np.uint8)

        # 计算梯度
        def compute_gradients(img):
            """计算图像梯度"""
            sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
            sobel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])

            pad_size = 1
            padded = np.pad(img, pad_size, mode='reflect')
            grad_x = np.zeros_like(img, dtype=np.float32)
            grad_y = np.zeros_like(img, dtype=np.float32)

            for i in range(img.shape[0]):
                for j in range(img.shape[1]):
                    region = padded[i:i + 3, j:j + 3]
                    grad_x[i, j] = np.sum(region * sobel_x)
                    grad_y[i, j] = np.sum(region * sobel_y)

            # 计算梯度幅值和方向
            magnitude = np.sqrt(grad_x ** 2 + grad_y ** 2)
            direction = np.arctan2(grad_y, grad_x) * 180 / np.pi
            direction = np.mod(direction, 180)  # 将角度限制在0-180度

            return magnitude, direction

        # 非极大值抑制
        def non_maximum_suppression(magnitude, direction):
            """非极大值抑制"""
            suppressed = np.zeros_like(magnitude)
            for i in range(1, magnitude.shape[0] - 1):
                for j in range(1, magnitude.shape[1] - 1):
                    angle = direction[i, j]
                    # 确定梯度方向最近的四个方向
                    if (0 <= angle < 22.5) or (157.5 <= angle <= 180):
                        neighbors = [magnitude[i, j - 1], magnitude[i, j + 1]]
                    elif 22.5 <= angle < 67.5:
                        neighbors = [magnitude[i - 1, j - 1], magnitude[i + 1, j + 1]]
                    elif 67.5 <= angle < 112.5:
                        neighbors = [magnitude[i - 1, j], magnitude[i + 1, j]]
                    else:  # 112.5 <= angle < 157.5
                        neighbors = [magnitude[i - 1, j + 1], magnitude[i + 1, j - 1]]

                    # 如果当前点是局部最大值，则保留
                    if magnitude[i, j] >= max(neighbors):
                        suppressed[i, j] = magnitude[i, j]

            return suppressed

        # 双阈值检测和边缘连接
        def double_threshold(suppressed, low_threshold, high_threshold):
            """双阈值检测和边缘连接"""
            strong_edges = suppressed >= high_threshold
            weak_edges = (suppressed >= low_threshold) & (suppressed < high_threshold)

            # 连接弱边缘
            edges = strong_edges.copy()
            for i in range(1, suppressed.shape[0] - 1):
                for j in range(1, suppressed.shape[1] - 1):
                    if weak_edges[i, j]:
                        # 检查8邻域是否有强边缘
                        if np.any(strong_edges[i - 1:i + 2, j - 1:j + 2]):
                            edges[i, j] = True

            return edges.astype(np.uint8) * 255

        # 执行边缘检测
        blurred = gaussian_blur(image)
        magnitude, direction = compute_gradients(blurred)
        suppressed = non_maximum_suppression(magnitude, direction)
        edges = double_threshold(suppressed, low_threshold, high_threshold)

        return edges
    # 检测边缘
    edges = canny_edge_detection(gray)

    # 创建输出图像
    h, w = img.shape[:2]
    if len(img.shape) == 3:
        sampled_img = np.zeros((h, w, img.shape[2]), dtype=img.dtype)
    else:
        sampled_img = np.zeros((h, w), dtype=img.dtype)

    # 非均匀采样
    for i in range(0, h, base_interval):
        for j in range(0, w, base_interval):
            # 检查当前区域是否有边缘
            region = edges[i:min(i + base_interval, h), j:min(j + base_interval, w)]
            if np.any(region > 0):  # 如果有边缘
                # 在边缘区域使用更密集的采样
                for ii in range(i, min(i + base_interval, h), edge_interval):
                    for jj in range(j, min(j + base_interval, w), edge_interval):
                        sampled_img[ii, jj] = img[ii, jj]
            else:
                # 在平滑区域使用基础采样
                sampled_img[i, j] = img[i, j]

    return sampled_img


def non_uniform_quantization_histogram(img, num_bins):
    """
    基于直方图的非均匀量化
    :param img: 输入图像
    :param num_bins: 量化级别数量
    :return: 量化后的图像
    """
    # 计算直方图
    if len(img.shape) == 3:
        # 对每个通道分别处理
        quantized_img = np.zeros_like(img)
        for c in range(img.shape[2]):
            channel = img[:, :, c]
            hist, bin_edges = np.histogram(channel.flatten(), bins=num_bins, density=True)

            # 计算累积分布函数
            cdf = hist.cumsum()
            cdf = cdf / cdf[-1]  # 归一化

            # # 创建查找表
            # lut = np.interp(np.arange(256), bin_edges[:-1] * 255, cdf * 255)
            # lut = lut.astype(np.uint8)
            #
            # # 应用查找表
            # quantized_img[:, :, c] = cv.LUT(channel, lut)

            # 创建查找表（不使用OpenCV的LUT）
            lut = np.zeros(256, dtype=np.uint8)
            for i in range(256):
                # 找到i在bin_edges中的位置
                bin_idx = np.searchsorted(bin_edges[:-1] * 255, i, side='right') - 1
                bin_idx = max(0, min(bin_idx, len(cdf) - 1))
                lut[i] = np.uint8(cdf[bin_idx] * 255)

            # 应用查找表（不使用OpenCV的LUT）
            for i in range(channel.shape[0]):
                for j in range(channel.shape[1]):
                    quantized_img[i, j, c] = lut[channel[i, j]]
    else:
        # 灰度图像
        hist, bin_edges = np.histogram(img.flatten(), bins=num_bins, density=True)

        # 计算累积分布函数
        cdf = hist.cumsum()
        cdf = cdf / cdf[-1]  # 归一化

        # # 创建查找表
        # lut = np.interp(np.arange(256), bin_edges[:-1] * 255, cdf * 255)
        # lut = lut.astype(np.uint8)
        #
        # # 应用查找表
        # quantized_img = cv.LUT(img, lut)

        # 创建查找表（不使用OpenCV的LUT）
        lut = np.zeros(256, dtype=np.uint8)
        for i in range(256):
            # 找到i在bin_edges中的位置
            bin_idx = np.searchsorted(bin_edges[:-1] * 255, i, side='right') - 1
            bin_idx = max(0, min(bin_idx, len(cdf) - 1))
            lut[i] = np.uint8(cdf[bin_idx] * 255)

        # 应用查找表（不使用OpenCV的LUT）
        quantized_img = np.zeros_like(img)
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                quantized_img[i, j] = lut[img[i, j]]
    return quantized_img


def adaptive_interval_settings(img):
    """
    根据图像分辨率自适应设置采样间隔
    """
    h, w = img.shape[:2]
    total_pixels = h * w

    # 基础间隔设置
    if total_pixels > 2000000:  # 高分辨率图像
        base_interval = 6
    elif total_pixels > 1000000:  # 中等分辨率
        base_interval = 4
    else:  # 低分辨率
        base_interval = 2

    # 边缘间隔设置（通常为1或接近1）
    edge_interval = 1

    return base_interval, edge_interval
